/**
 * 14/05/2010
 * @author Kal�u Caminha
 * @author William Rodrigues
 * @author Rodrigo Coelho
 */
package principal;

import semantico.*;
import gals.*;
import java.util.Iterator;
import java.util.Stack;
/**
 * Classe utilizada para concentrar a��es de an�lise sem�ntica
 *
 * @author kaleu
 */
public class AnalisadorSemantico {    

    protected TabelaSimbolos ts;
    //Token atual salvo sempre que uma a��o sem�ntica � encontrada
    protected Token token;
    protected int nivelAtual;
    protected int tipoPreDefinido;
    protected int tipoConst = -1;
    protected String contextoLID;
    protected int MPP;
    protected int NPF;
    protected int NPA;
    public Vetor vetorTemp = new Vetor();
    protected Constante ultimaConstante;
    protected Procedimento ultimoProcedimento;
    protected String valorDeConst;
    protected int tipoAtual;
    protected TipoVariavel tipoVariavel;
    protected int posicaoDeId;
    protected String contextoEXPR;
    protected Token tempidReferenteaPosicaoId;
    public Expressao expr = new Expressao();
    protected Operador opAtual = new Operador();
    protected Operador[] opsalvos = new Operador[100];
    protected int contadorDeOp = 0;
    protected TipoVariavel tipoFator;
    protected TipoVariavel tipoTermo;
    protected int POSID;

    protected int procedimentoChamadoID;

    protected TipoVariavel tipoVar;
    protected Stack pilhaTipoVarIndexada = new Stack();


    public boolean temTipoVarIndexada() {
        return !this.pilhaTipoVarIndexada.empty();
    }

    public TipoVariavel getTipoVarIndexada() {
        return (TipoVariavel)this.pilhaTipoVarIndexada.peek();
    }

    public void addTipoVarIndexada(TipoVariavel pilhaTipoVarIndexada){
        this.pilhaTipoVarIndexada.push(pilhaTipoVarIndexada);
    }

    public void removeTipoVarIndexada() {
        this.pilhaTipoVarIndexada.pop();
    }

    protected int numeroDeIndices;
    protected TipoVariavel tipoLadoEsq;

    protected Stack varControleParaFaca = new Stack();
    protected boolean ehEscopoParaFaca;

    public boolean isEhEscopoParaFaca() {
        return !this.varControleParaFaca.empty();
    }    

    public Identificador getVarControleParaFaca() {
        return (Identificador)this.varControleParaFaca.peek();
    }

    public void addVarControleParaFaca(Identificador varControleParaFaca) {
        this.varControleParaFaca.push(varControleParaFaca);
    }

    public void removeVarControleParaFaca() {
        this.varControleParaFaca.pop();
    }

    protected Stack pilhaVetorTemp = new Stack();


    public boolean temVetorTemp() {
        return !this.pilhaVetorTemp.empty();
    }

    public Vetor getPilhaVetorTemp() {
        System.out.println("Pega vetor atual: "+(Vetor)this.pilhaVetorTemp.peek());
        return (Vetor)this.pilhaVetorTemp.peek();
    }

    public void addVetorTemp(Vetor varTemp) {
        System.out.println("Adiciona vetor a pilha: "+varTemp);
        this.pilhaVetorTemp.push(varTemp);
    }

    public void removeVetorTemp() {
        System.out.println("Remove Vetor da Pilha: "+this.pilhaVetorTemp.pop());
    }

    public boolean ehIdentificadorParaFaca(Identificador i){
        for(Iterator it = this.varControleParaFaca.iterator(); it.hasNext();){
            Identificador temp = (Identificador)it.next();
            if(i.getNome().equals(temp.getNome())){
                return true;
            }            
        }
        return false;

    }

	protected boolean ehFuncao = false;
	protected boolean funcaoTemComandoAtribuicao = false;


	public boolean saoTiposCompativeis(TipoVariavel tipo1, TipoVariavel tipo2){
        if(this.getOpAtual().getOp().equals("div")){
            return tipo1.getTipoVariavel() == TipoVariavel.NUM_INT && tipo2.getTipoVariavel() == TipoVariavel.NUM_INT;
        }

		if(tipo1.getTipoVariavel() == tipo2.getTipoVariavel()){
			return true;
		} else if (tipo1.getTipoVariavel() == TipoVariavel.NUM_REAL && tipo2.getTipoVariavel() == TipoVariavel.NUM_INT){
			return true;
		} else if (tipo1.getTipoVariavel() == TipoVariavel.NUM_INT && tipo2.getTipoVariavel() == TipoVariavel.NUM_REAL){
			return true;
		} else if (tipo1.getTipoVariavel() == TipoVariavel.CADEIA && tipo2.getTipoVariavel() == TipoVariavel.CARACTER){
			return true;
		} else if (tipo1.getTipoVariavel() == TipoVariavel.CADEIA && tipo2.getTipoVariavel() == TipoVariavel.LITERAL){
			return true;
		}else if (tipo1.getTipoVariavel() == TipoVariavel.LITERAL && tipo2.getTipoVariavel() == TipoVariavel.CADEIA){
			return true;
		}else if (tipo1.getTipoVariavel() == TipoVariavel.LITERAL && tipo2.getTipoVariavel() == TipoVariavel.CARACTER){
			return true;
		}else if (tipo1.getTipoVariavel() == TipoVariavel.CARACTER && tipo2.getTipoVariavel() == TipoVariavel.LITERAL){
			return true;
		}else if (tipo1.getTipoVariavel() == TipoVariavel.CARACTER && tipo2.getTipoVariavel() == TipoVariavel.CADEIA){
			return true;
		}else {
			return false;
		}
	}

	public TipoVariavel getTipoResultadoOperacao(TipoVariavel tipo1, TipoVariavel tipo2){

        System.out.println("Pega Tipo Resultado: "+tipo1+" - "+tipo2+" - "+this.getOpAtual().getOp());

		if(this.getOpAtual().getOp().equals("div")){
			return new TipoPreDefinidoTipoVariavel(TipoVariavel.NUM_INT);
		} else if(this.getOpAtual().getOp().equals("e")){
			return new TipoPreDefinidoTipoVariavel(TipoVariavel.BOOL);
		} else if(this.getOpAtual().getOp().equals("/")){
            System.out.println("Pega Tipo Resultado: "+tipo1+" - "+tipo2+" - "+this.getOpAtual().getOp());
			return new TipoPreDefinidoTipoVariavel(TipoVariavel.NUM_REAL);
		} else if(this.getOpAtual().getOp().equals("*")){
			return tipo1;



		} else if(this.getOpAtual().getOp().equals("+")){
			return tipo1;

		} else if(this.getOpAtual().getOp().equals("-")){

			return tipo1;

		} else if(this.getOpAtual().getOp().equals("ou")){
			return new TipoPreDefinidoTipoVariavel(TipoVariavel.BOOL);
		}else {
			return null;
		}

		// "+" #58 | "-" #59 | ou
	}

    public TipoVariavel getTipoLadoEsq() {
        return tipoLadoEsq;
    }



    public void setTipoLadoEsq(TipoVariavel tipoLadoEsq) {
        this.tipoLadoEsq = tipoLadoEsq;
    }
    

    public int getNumeroDeIndices() {
        return numeroDeIndices;
    }

    public void setNumeroDeIndices(int numeroDeIndices) {
        this.numeroDeIndices = numeroDeIndices;
    }
    

    public TipoVariavel getTipoFator() {
        return tipoFator;
    }

    public void setTipoFator(TipoVariavel tipoFator) {
        this.tipoFator = tipoFator;
    }

    public TipoVariavel getTipoTermo() {
        return tipoTermo;
    }

    public void setTipoTermo(TipoVariavel tipoTermo) {
        this.tipoTermo = tipoTermo;
    }


    public void setOpAtual(Operador opAtual) {
        this.opAtual = opAtual;
    }

    public Operador getOpAtual() {
        return opAtual;
    }

    public void setContadorDeOp(int contadorDeOp) {
        this.contadorDeOp = contadorDeOp;
    }

    public int getContadorDeOp() {
        return contadorDeOp;
    }

    public void setOpsalvos(Operador[] opsalvos) {
        this.opsalvos = opsalvos;
    }


    public void guardarOperador() {
        opsalvos[contadorDeOp] = opAtual;
        contadorDeOp++;
    }

    public Operador[] getOpsalvos() {
        return opsalvos;
    }
	
    public Expressao getExpr() {
        return expr;
    }

    public void setExpr(Expressao expr) {
        this.expr = expr;
    }


    public Token getTempidReferenteaPosicaoId() {
        return tempidReferenteaPosicaoId;
    }

    public void setTempidReferenteaPosicaoId(Token tempidReferenteaPosicaoId) {
        this.tempidReferenteaPosicaoId = tempidReferenteaPosicaoId;
    }

    
    
    public String getContextoEXPR() {
        return contextoEXPR;
    }

    public void setContextoEXPR(String contextoEXPR) {
        this.contextoEXPR = contextoEXPR;
    }

    public int getPosicaoDeId() {
        return posicaoDeId;
    }

    public void setPosicaoDeId(int posicaoDeId) {
        this.posicaoDeId = posicaoDeId;
    }

    public Vetor getVetorTemp() {
        return vetorTemp;
    }

    public void setVetorTemp(Vetor vetorTemp) {
        this.vetorTemp = vetorTemp;
    }
    
    public String getValorDeConst() {
        return valorDeConst;
    }

    public void setValorDeConst(String valorDeConst) {
        this.valorDeConst = valorDeConst;
    }

    public AnalisadorSemantico(){
        ts = new TabelaSimbolos();
        this.nivelAtual = 0;
    }
    

    public void verificaIdDeclarado() throws SemanticError{
        int item = ts.temSimbolo(token.getLexeme(), this.getNivelAtual());
        if(item == 0){
            this.erro("ID "+token.getLexeme()+" ja foi declarado como identificador do programa.");
        } else if (item > 0) {
            this.erro("ID "+token.getLexeme()+" ja foi declarado.");
        }
    }

    public int verificaIdNaoDeclarado() throws SemanticError{
        int item = ts.temSimbolo(token.getLexeme(), this.getNivelAtual());
        if (item == -1) {
            System.err.println("Bug here?");
            this.erro("ID "+token.getLexeme()+" n�o foi declarado.");
        }
        return item;
    }

    /* ERROR */




    public void erro(String msg, int position) throws SemanticError {
        throw new SemanticError(msg, position);
    }

    public void erro(String msg) throws SemanticError {
        throw new SemanticError(msg, this.getToken().getPosition(), this.getToken());
    }


    public int getTipoConst() {
        return tipoConst;
    }

    public String getContextoLID() {
        return contextoLID;
    }



    public void setTipoConst(int tipoConst) {
        this.tipoConst = tipoConst;
    }

    public void setContextoLID(String contextoLID) {
        this.contextoLID = contextoLID;
    }


    public int getMPP() {
        return MPP;
    }

    public void setMPP(int MPP) {
        this.MPP = MPP;
    }

    public int getTipoAtual() {
        return tipoAtual;
    }

    public void setTipoAtual(int tipoAtual) {
        this.tipoAtual = tipoAtual;
    }


    



    public int getNPF() {
        return NPF;
    }

    public void setNPF(int NPF) {
        this.NPF = NPF;
    }






    /* GET e SET */

        


	public Procedimento getUltimoProcedimento() {
		return this.getTs().getUltimoProcedimento();
		//return ultimoProcedimento;
	}

	public void setUltimoProcedimento(Procedimento ultimoProcedimento) {
		this.ultimoProcedimento = ultimoProcedimento;
	}

    public Constante getUltimaConstante() {
        return ultimaConstante;
    }

    public void setUltimaConstante(Constante ultimaConstante) {
        this.ultimaConstante = ultimaConstante;
    }
    
    public int getNivelAtual() {
        return nivelAtual;
    }

    public void setNivelAtual(int nivelAtual) {
        this.nivelAtual = nivelAtual;
    }

    public int getTipoPreDefinido() {
        return tipoPreDefinido;
    }

    public void setTipoPreDefinido(int tipoConst) {
        this.tipoPreDefinido = tipoConst;
    }

    public Token getToken() {
        return token;
    }

    public void setToken(Token token) {
        this.token = token;
    }

    public TabelaSimbolos getTs() {
        return ts;
    }

    public void setTs(TabelaSimbolos ts) {
        this.ts = ts;
    }

	public TipoVariavel getTipoVariavel() {
		return tipoVariavel;
	}

	public void setTipoVariavel(TipoVariavel tipoVariavel) {
		this.tipoVariavel = tipoVariavel;
	}

	public TipoVariavel getTipoVar() {
		return tipoVar;
	}

	public void setTipoVar(TipoVariavel tipo) {
		this.tipoVar = tipo;
	}

	public int getPOSID() {
		return POSID;
	}

	public void setPOSID(int POSID) {
		this.POSID = POSID;
	}

	public int getProcedimentoChamadoID() {
		return procedimentoChamadoID;
	}

	public void setProcedimentoChamadoID(int procedimentoChamadoID) {
		this.procedimentoChamadoID = procedimentoChamadoID;
	}

	public int getNPA() {
		return NPA;
	}

	public void setNPA(int NPA) {
		this.NPA = NPA;
	}

	public boolean isEhFuncao() {
		return ehFuncao;
	}

	public void setEhFuncao(boolean ehFuncao) {
		this.ehFuncao = ehFuncao;
	}

	public boolean isFuncaoTemComandoAtribuicao() {
		return funcaoTemComandoAtribuicao;
	}

	public void setFuncaoTemComandoAtribuicao(boolean funcaoTemComandoAtribuicao) {
		this.funcaoTemComandoAtribuicao = funcaoTemComandoAtribuicao;
	}

	
	


}